#pragma once
#ifndef POINTOPERATION_H
#define POINTOPERATION_H

// #include "gmp.h"
#include <gmp.h>

// 定义点
typedef struct Point
{
	// 点的 x 坐标
	mpz_t x;
	// 点的 y 坐标
	mpz_t y;
} point[1], *point_ptr;

/**
 * 初始化点的坐标.
 *
 * \param point1 点
 */
void point_init(point point1);

/**
 * 初始化点的坐标.
 *
 * \param point1 点
 */
void point_inits(point_ptr point1, ...);

/**
 * 释放点的坐标所占的空间.
 *
 * \param point1 点
 */
void point_clear(point point1);

/**
 * 释放点的坐标所占的空间.
 *
 * \param point1 点
 * \param 可变参数 全是点+NULL
 */
void point_clears(point_ptr point1, ...);

/**
 * 判断点是否值相等.
 *
 * \param point1 第一个点
 * \param point2 第二个点
 * \return x,y的值都相等，则返回0。有一个不相等，则返回-1
 */
int point_cmp(point point1, point point2);

/**
 * 给点赋值.
 *
 * \param point1
 * \param point2
 */
void point_set(point point1, point point2);

/**
 * 初始化和赋值.
 *
 * \param point1
 * \param point2
 */
void point_init_set(point point1, point point2);

/**
 * 点加运算 ret = point1 + point2.
 *
 * \param point1 点P
 * \param point2 点Q
 * \param p 模数p
 * \param a 一次项系数
 * \return 点R
 */
void point_add(point ret, point point1, point point2, mpz_t a, mpz_t p);

/**
 * 点加的逆运算 ret = point1 - point2.
 *
 * \param point1 点P
 * \param point2 点Q
 * \param p 模数p
 * \param a 一次项系数
 * \return 点R
 */
void point_sub(point ret, point point1, point point2, mpz_t a, mpz_t p);

/**
 * 多倍点运算。利用快速幂迭代法求解.
 *
 * \param ret 输出结果
 * \param point1 点
 * \param k 倍数
 * \param a 一次项系数
 * \param p 模数p
 */
void point_mul(point ret, point point1, mpz_t k, mpz_t a, mpz_t p);

/**
 * 对 a^b mod p 求逆.
 *
 * \param ret 返回值
 * \param a 需要求逆元素的底数
 * \param b 需要求逆元素的指数
 * \param p 模数p
 * \return
 */
void inverse(mpz_t ret, mpz_t a, mpz_t b, mpz_t p);

/**
 * 费马小定理求逆。a^(p-2)=a^(-1) mod p.
 *
 * \param a 需要求逆得的元素
 * \param p 模数p
 * \return
 */
void inverse_by_p(mpz_t ret, mpz_t a, mpz_t p);

/**
 * 8.1.1 有限域上的椭圆曲线。计算椭圆曲线上的点.
 *
 * \param a 一次项系数
 * \param b 常数项
 * \param p 模数
 */
void cal_elliptic_curve_point(int a, int b, int mod);

#endif